package com.qdxwx.data.service.area;

import com.qdxwx.data.mapper.area.AreaMapper;
import com.qdxwx.models.area.Area;
import com.qdxwx.models.area.AreaFull;
import com.qdxwx.models.area.AreaLevel;
import com.qdxwx.models.dto.NodeSmall;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Qdx NetSchool Platform
 * @author qdxwx
 * @updateTime 2022/5/25
 * @description
 */
@Service
public class AreaServiceImpl implements AreaService {

    @Autowired
    private AreaMapper areaMapper;

    @Override
    public AreaFull getAreaFull(int areaId) {
        Area area = get(areaId);
        if (area == null) {
            return null;
        }
        AreaFull areaFull = new AreaFull();
        areaFull.setId(area.getId());
        areaFull.setName(area.getName());
        areaFull.setShortName(area.getShortName());
        areaFull.setSortOrder(area.getSortOrder());
        areaFull.setLevel(area.getLevel());
        areaFull.setParentId(area.getParentId());
        areaFull.setChildCount(area.getChildCount());
        if (area.getLevel() == AreaLevel.CITY.ordinal()) {
            areaFull.setProvinceId(area.getParentId());
            areaFull.setCityId(area.getId());
        } else if (area.getLevel() == AreaLevel.COUNTY.ordinal()) {
            Area pArea = get(area.getParentId());
            if (pArea.getLevel() == AreaLevel.PROVINCE.ordinal()) {
                areaFull.setProvinceId(pArea.getId());
                areaFull.setCityId(area.getId());
            } else {
                areaFull.setProvinceId(pArea.getParentId());
                areaFull.setCityId(pArea.getId());
                areaFull.setCountyId(area.getId());
            }
        } else {
            areaFull.setProvinceId(areaId);
        }
        return areaFull;
    }

    @Override
    public Area get(int id) {
        if (id < 1) return null;
        return areaMapper.selectById(id);
    }

    @Override
    public Area getParent(int id) {
        Area area = get(id);
        if (area != null) return get(area.getParentId());
        return null;
    }

    @Override
    public List<Area> getChildren(int parentId) {
        return areaMapper.selectChildren(parentId);
    }

    @Override
    public List<Area> getAncestors(int id, boolean withSelf) {
        List<Area> areas = new ArrayList<>(0);
        if (id < 1) {
            return areas;
        }
        Area area = get(id);
        if (area == null) return areas;
        int parentId = area.getParentId();
        int count = 0;//防止数据错乱进入死循环
        while (parentId > 0 && count < 10) {
            count++;
            Area parent = get(parentId);
            if (parent == null) break;
            parentId = parent.getParentId();
            areas.add(0, parent);
        }
        if (withSelf) {
            areas.add(area);
        }
        return areas;
    }

    @Override
    public List<Area> getDescendants(int id, boolean withSelf) {
        List<Area> areas = new ArrayList<>(0);
        List<Area> children = getChildren(id);
        if (children != null) {
            for (Area area : children) {
                areas.add(area);
                if (area.getChildCount() > 0)
                    areas.addAll(getDescendants(area.getId(), false));
            }
        }
        if (withSelf && id > 0) {
            areas.add(0, get(id));
        }
        return areas;
    }

    @Override
    public Collection<Integer> getDescendantIds(int id) {
        if (id < 1) return null;
        List<Area> areas = getDescendants(id, true);
        List<Integer> ids = new ArrayList<>();
        for (Area area : areas) {
            ids.add(area.getId());
        }
        return ids;
    }

    @Override
    public NodeSmall[] getAreaTreeNode(int parentId, int depth, int withRoot, int withAllChina) {
        if (parentId < 0)
            return new NodeSmall[0];
        List<Area> areas;
        if (depth == 1) {
            areas = getChildren(parentId);
            if (withRoot == 1 && parentId > 0) {
                areas.add(0, get(parentId));
            }
        } else {
            areas = getDescendants(parentId, withRoot == 1);
        }
        if (areas.isEmpty()) return new NodeSmall[0];
        if (parentId == 0) {
            if (withAllChina == 1) {
                areas.add(0, Area.allChina());
            }
            if (withRoot == 1) {
                Area root = new Area();
                root.setId(0);  //Virtual root id: 0
                root.setName("全部");
                root.setShortName("全部");
                root.setParentId(-1);
                areas.add(0, root);
            }
        }
        int rows = areas.size();
        NodeSmall[] nodes = new NodeSmall[rows];
        int i = 0;
        for (Area area : areas) {
            NodeSmall node = new NodeSmall();
            node.setId(String.valueOf(area.getId()));
            node.setName(area.getName());
            node.setpId(String.valueOf(area.getParentId()));
            nodes[i++] = node;
        }
        return nodes;
    }

    @Override
    public boolean containsChild(int parentId, String childName) {
        if (parentId < 0 || childName == null) return false;
        int rows = areaMapper.containsChild(parentId, childName);
        return rows > 0;
    }

    @Override
    public int save(Area area) {
        if (area == null) return 0;

        if (area.getId() == 0) {
            int parentId = area.getParentId();
            if (parentId > 0) {
                Area parent = areaMapper.selectById(parentId);
                if (parent == null) {
                    throw new RuntimeException("Parent area not found: id=" + parentId);
                }
                if (parent.getLevel() == AreaLevel.STREET.ordinal()) {
                    throw new RuntimeException("Parent area is last node: id=" + parentId);
                }
                area.setLevel(parent.getLevel() + 1);
            } else {
                area.setLevel(AreaLevel.PROVINCE.ordinal());
            }
            if (containsChild(parentId, area.getName())) {
                throw new IllegalArgumentException("Area already exists: name = " + area.getName());
            }
            int ret = areaMapper.insert(area);
            if (parentId > 0) {
                areaMapper.changeChildCount(parentId, 1);
            }
            return ret;
        } else {
            area.setChildCount(areaMapper.countChildren(area.getId()));
            return areaMapper.update(area);
        }
    }

    @Override
    public int delete(int id) {
        if (id > 0) {
            Area area = get(id);
            if (area == null) return 0;
            int parentId = area.getParentId();
            int ret = areaMapper.delete(id);
            if (parentId > 0) {
                areaMapper.changeChildCount(parentId, -1);
            }
            return ret;
        }
        return 0;
    }
}
